package xcmg.device.service.warehouse;

import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageInfo;
import xcmg.device.service.order.SubcontractingOrderService;
import yb.ecp.fast.infra.util.PageHelperPlus;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import xcmg.device.dao.entity.MaterialLocationRelationDO;
import xcmg.device.dao.entity.agent.AgentAllotDetailDO;
import xcmg.device.dao.entity.barcode.BarcodeManageDO;
import xcmg.device.dao.entity.company.CompanyInfoDO;
import xcmg.device.dao.entity.company.CompanySupplierDO;
import xcmg.device.dao.entity.initialInventory.InitialInventoryDetailDO;
import xcmg.device.dao.entity.logistics.SendBillDO;
import xcmg.device.dao.entity.purchase.PurchaseInboundDO;
import xcmg.device.dao.entity.purchase.PurchaseInboundDetailDO;
import xcmg.device.dao.entity.salesReturn.SalesReturnInDetailDO;
import xcmg.device.dao.entity.warehouse.AbnormalInDetailDO;
import xcmg.device.dao.entity.warehouse.WarehouseInboundDO;
import xcmg.device.dao.entity.warehouse.WarehouseInboundDetailDO;
import xcmg.device.dao.entity.warehouse.WarehouseInboundRecordDO;
import xcmg.device.dao.mapper.BarcodeManageMapper;
import xcmg.device.dao.mapper.CompanyInfoMapper;
import xcmg.device.dao.mapper.CompanySupplierMapper;
import xcmg.device.dao.mapper.MaterialLocationRelationMapper;
import xcmg.device.dao.mapper.warehouse.WarehouseAreaLocationDOMapper;
import xcmg.device.dao.mapper.warehouse.WarehouseDOMapper;
import xcmg.device.dao.mapper.warehouse.WarehouseInboundDetailMapper;
import xcmg.device.dao.mapper.warehouse.WarehouseInboundMapper;
import xcmg.device.dao.mapper.warehouse.WarehouseInboundRecordMapper;
import xcmg.device.infra.ErrorCode;
import xcmg.device.infra.ExportUtil;
import xcmg.device.infra.enums.BarcodeStatus;
import xcmg.device.infra.enums.BillDesc;
import xcmg.device.service.agent.AgentAllotDetailService;
import xcmg.device.service.agent.ServiceBorrowInService;
import xcmg.device.service.agentReturn.AgentReturnService;
import xcmg.device.service.barcode.BarcodeService;
import xcmg.device.service.basic.MaterialsService;
import xcmg.device.service.borrowMaterial.BorrowMaterialService;
import xcmg.device.service.buyBack.BackInboundService;
import xcmg.device.service.delivery.ReceiptInService;
import xcmg.device.service.logistics.SendBillService;
import xcmg.device.service.materialsSchedule.MaterialsScheduleService;
import xcmg.device.service.purchase.PurchaseInboundService;
import xcmg.device.service.sale.ReturnInService;
import xcmg.device.service.sale.SaleReverseDetailService;
import xcmg.device.service.threeGuaranteesPur.ThreeReverseDetailService;
import xcmg.device.service.vo.basic.MaterialLocationRelationVO;
import xcmg.device.service.vo.basic.MaterialsVO;
import xcmg.device.service.vo.warehouse.InOutNumVO;
import xcmg.device.service.vo.warehouse.WarehouseInboundAddVO;
import xcmg.device.service.vo.warehouse.WarehouseInboundDetailVO;
import xcmg.device.service.vo.warehouse.WarehouseInboundRecordAddVO;
import xcmg.device.service.vo.warehouse.WarehouseInboundRecordBatchAddVO;
import xcmg.device.service.vo.warehouse.WarehouseInboundRecordVO;
import xcmg.device.service.warehouse.allot.RegionAllotDetailService;
import xcmg.device.util.CompanyUtil;
import yb.ecp.fast.feign.FastGenClient;
import yb.ecp.fast.infra.infra.ActionResult;
import yb.ecp.fast.infra.infra.PageCommonVO;
import yb.ecp.fast.infra.infra.SearchCommonVO;
import yb.ecp.fast.infra.infra.log.LogHelper;
import yb.ecp.fast.infra.util.ListUtil;
import yb.ecp.fast.infra.util.StringUtil;

import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class WarehouseInboundRecordService {

    @Autowired
    private WarehouseInboundRecordMapper warehouseInboundRecordMapper;

    @Autowired
    private WarehouseInventoryService warehouseInventoryService;

    @Autowired
    private WarehouseInboundDetailService warehouseInboundDetailService;

    @Autowired
    private InitialInventoryService initialInventoryService;

    @Autowired
    private FastGenClient fastGenClient;

    @Autowired
    private BarcodeManageMapper barcodeManageMapper;

    @Autowired
    private WarehouseInboundDetailMapper warehouseInboundDetailMapper;

    @Autowired
    private BarcodeService barcodeService;

    @Autowired
    private AbnormalInDetailService abnormalInDetailService;

    @Autowired
    private SubcontractingOrderService subcontractingOrderService;

    @Autowired
    private WarehouseAreaLocationDOMapper warehouseAreaLocationDOMapper;

    @Autowired
    private CommonService commonService;

    @Autowired
    private HttpServletResponse response;

    @Autowired
    private RegionAllotDetailService regionAllotDetailService;

    @Autowired
    private AgentAllotDetailService agentAllotDetailService;

    @Autowired
    private WarehouseInboundMapper warehouseInboundMapper;

    @Autowired
    private SaleReverseDetailService saleReverseDetailService;

    @Autowired
    private ReturnInService returnInService;

    @Lazy
    @Autowired
    private PurchaseInboundService purchaseInboundService;

    @Autowired
    private WarehouseInboundService warehouseInboundService;

    @Autowired
    private MaterialsScheduleService materialsScheduleService;

    @Autowired
    private DeliveryInstructionDetailService deliveryInstructionDetailService;

    @Autowired
    private ThreeReverseDetailService threeReverseDetailService;

    @Autowired
    private MaterialLocationRelationMapper materialLocationRelationMapper;

    @Autowired
    private BackInboundService backInboundService;

    @Autowired
    private SendBillService sendBillService;

    @Autowired
    private ReceiptInService receiptInService;
    @Autowired
    private ServiceBorrowInService serviceBorrowInService;
    @Autowired
    private CompanyInfoMapper companyInfoMapper;
    @Autowired
    private CompanySupplierMapper companySupplierMapper;
    @Autowired
    private MaterialsService materialsService;
    @Autowired
    private WarehouseDOMapper warehouseDOMapper;
    @Autowired
    private AgentReturnService agentReturnService;

    @Autowired
    private BorrowMaterialService borrowMaterialService;

    private static final Logger logger = LoggerFactory.getLogger(WarehouseInboundRecordService.class);

    /**
     * @Author: WangKe
     * @Description: 批量新增入库记录
     * @Date: 2018/3/14 0014
     */
    @Transactional(rollbackFor = Exception.class)
    public ErrorCode batchAdd(WarehouseInboundRecordBatchAddVO warehouseInboundRecordBatchAddVO, String userId, String orgId) throws Exception {
        if (ListUtil.isNullOrEmpty(warehouseInboundRecordBatchAddVO.getRecordList())) {
            return ErrorCode.IllegalArument;
        }
        ErrorCode errorCode = ErrorCode.Success;
        List<WarehouseInboundRecordAddVO> recordAddVOList = warehouseInboundRecordBatchAddVO.getRecordList();
        int size = recordAddVOList.size();
        if (size == 1){
            try {
                errorCode = this.add(recordAddVOList.get(0), userId, orgId);
            } catch (Exception e) {
                logger.error("入库异常：",e);
                throw new Exception("index&&0&&" + e.getMessage());
            }

            if (errorCode.getCode() != 0 && errorCode.getCode() != 5008) {
                logger.error("入库异常：" + errorCode.getDesc());
                throw new Exception("index&&0&&" + errorCode.getDesc());
            }
        }else{
            for (int i = 0; i < recordAddVOList.size(); i++) {
                WarehouseInboundRecordAddVO recordAddVO = recordAddVOList.get(i);
                try {
                    errorCode = this.add(recordAddVO, userId, orgId);
                } catch (Exception e) {
                    logger.error("入库异常：",e);
                    if (errorCode.getCode() == 5008){
                        continue;
                    }
                    throw new Exception("index&&" + i + "&&" + e.getMessage());
                }

                if (errorCode.getCode() != 0) {
                    if (errorCode.getCode() == 5008){
                        continue;
                    }
                    logger.error("入库异常：" + errorCode.getDesc());
                    throw new Exception("index&&" + i + "&&" + errorCode.getDesc());
                }
            }
        }

        return errorCode;
    }

    /**
     * @Author: WangKe
     * @Description: 新增入库记录
     * @Date: 15:19 2018/1/17 0017
     */
    @Transactional(rollbackFor = Exception.class)
    public ErrorCode add(WarehouseInboundRecordAddVO warehouseInboundRecordVO, String userId, String orgId) throws Exception {
        ActionResult<String> textResult = fastGenClient.textGuid();
        if (textResult.getCode() != ErrorCode.Success.getCode()) {
            return ErrorCode.IllegalArument;
        }
        if (StringUtil.isNullOrEmpty(warehouseInboundRecordVO.getBusinessOrder())) {
            throw new Exception("未找到入库单，请检查业务单号是否正确");
        }

        if (warehouseInboundRecordVO.getAmount().compareTo(BigDecimal.ZERO) <= 0) {
            throw new Exception("入库数量必须大于0");
        }

        //根据条码获取条码实体
        BarcodeManageDO barcode = barcodeManageMapper.item(warehouseInboundRecordVO.getBarCode(), orgId);
        if (barcode == null) {
            return ErrorCode.WarehouseBarcodeNotFound;
        }
        if (barcode.getBarcodeFlag() == 0) {
            return ErrorCode.TotalBarcodeNotEable;
        }

        //判断条码是否已经扫描入库
        if ("1".equals(barcode.getBarcodeStatus())) {
            return ErrorCode.WarehouseInboundDuplicate;
        }

        //实际发货数量大于计划数量时，返回错误信息
        if (warehouseInboundRecordVO.getAmount().compareTo(barcode.getCurrentQty()) > 0) {
            return ErrorCode.InboundNumError;
        }

        if ("0".equals(barcode.getBarcodeStatus())) {
            if (!warehouseInboundRecordVO.getBusinessOrder().equals(barcode.getBillNo())) {
                return ErrorCode.MaterialsIsNotThisBill;
            }
        }

        //扫描入库时如果实际入库数量小于条码数量，更新条码数量
        if (barcode.getCurrentQty().compareTo(warehouseInboundRecordVO.getAmount()) > 0) {
            barcodeService.updateBarcodeNum(barcode, warehouseInboundRecordVO.getAmount(), orgId);
        }

        //根据业务单号和零件编码查询入库详情记录
        WarehouseInboundDetailVO tempVO = new WarehouseInboundDetailVO();
        tempVO.setBusinessOrder(warehouseInboundRecordVO.getBusinessOrder());
        tempVO.setMaterialNo(barcode.getMaterialsNo());
        tempVO.setOrgId(orgId);
        if ("0".equals(barcode.getBarcodeStatus())){
            tempVO.setRowNo(barcode.getRowNo());
        }
        List<WarehouseInboundDetailDO> detailList = warehouseInboundDetailMapper.list(tempVO);
        if (ListUtil.isNullOrEmpty(detailList)) {
            return ErrorCode.MaterialsIsNotThisBill;
        }
        WarehouseInboundDetailDO inboundDetail = detailList.get(0);
        WarehouseInboundRecordDO warehouseInboundRecordDO = new WarehouseInboundRecordDO();
        BeanUtils.copyProperties(inboundDetail, warehouseInboundRecordDO);
        BeanUtils.copyProperties(warehouseInboundRecordVO, warehouseInboundRecordDO);

        if (inboundDetail.getStatus() == 2) {
            throw new Exception("此零件状态已完成");
        }
        if (inboundDetail.getStatus() == 3) {
            throw new Exception("此零件状态已结单");
        }

        //根据储位获取仓库、仓库编码
        String locationCode = warehouseInboundRecordVO.getLocationCode();
        if (locationCode.toCharArray()[0] == '\uFEFF') {
            locationCode = locationCode.substring(1);
            warehouseInboundRecordDO.setLocationCode(locationCode);
        }
        Map<String, Object> warehouseMap = warehouseAreaLocationDOMapper.findAllCode(locationCode, orgId);
        if (warehouseMap == null || warehouseMap.get("WAREHOUSE_CODE") == null || warehouseMap.get("AREA_CODE") == null) {
            return ErrorCode.WarehouseLocationCodeError;
        }
        warehouseInboundRecordDO.setWarehouseCode((String) warehouseMap.get("WAREHOUSE_CODE"));
        warehouseInboundRecordDO.setAreaCode((String) warehouseMap.get("AREA_CODE"));

        CompanyInfoDO companyInfoDO = companyInfoMapper.item(orgId);
        Integer isBarcode = companyInfoDO.getIsBarcode();
        int countIsBarCode = warehouseDOMapper.countIsBarCode(orgId, warehouseInboundRecordDO.getWarehouseCode());
        if ((null == isBarcode || 0 == isBarcode) && countIsBarCode <= 0){//非条码化企业且仓库不允许条码化返回错误信息
            throw new Exception(ErrorCode.NonBarcodedWarehousesNotAllowBarCodeEntry.getDesc());
        }

        //判断扫描储位所属仓库是否和入库单中仓库一致
        WarehouseInboundDO inboundDO = warehouseInboundMapper.selectByOrder(warehouseInboundRecordVO.getBusinessOrder(), orgId);
        if (inboundDO == null) {
            throw new Exception("未找到入库单，请检查业务单号是否正确");
        }

        if (inboundDO.getStatus() != null && inboundDO.getStatus() == 4) {
            throw new Exception("业务单据已作废！");
        }
        if (inboundDO.getStatus() != null && inboundDO.getStatus() == 2) {
            throw new Exception("业务单据已完成！");
        }
        if (inboundDO.getStatus() != null && inboundDO.getStatus() == 3) {
            throw new Exception("业务单据已结单！");
        }
        if (!StringUtil.isNullOrEmpty(inboundDO.getWarehouseCode()) &&
                !inboundDO.getWarehouseCode().equals(warehouseInboundRecordDO.getWarehouseCode())) {
            return ErrorCode.LocationCodeError;
        }
        if (!StringUtil.isNullOrEmpty(inboundDO.getInArea()) &&
                !inboundDO.getInArea().equals(warehouseInboundRecordDO.getAreaCode())) {
            return ErrorCode.LocationCodeError;
        }

        //计算成本
        BigDecimal cost = null;
//        if (inboundDetail.getTotalPrice() != null) {
//            BigDecimal v1 = inboundDetail.getTotalPrice();
//            BigDecimal v2 = inboundDetail.getAmount();
//            //结果 6位小数、四舍五入
//            cost = v1.divide(v2, 6, BigDecimal.ROUND_HALF_UP);
//        }

        warehouseInboundRecordDO.setId(textResult.getValue());
        warehouseInboundRecordDO.setBarCode(barcode.getBarcode());
        warehouseInboundRecordDO.setCreateDate(new Date());
        warehouseInboundRecordDO.setCreaterId(userId);
        warehouseInboundRecordDO.setOrgId(orgId);
        warehouseInboundRecordDO.setCreaterName(commonService.getUserName(userId));
        warehouseInboundRecordDO.setRowNo(barcode.getRowNo());
        //如果是回购入库单，入库就将库存冻结
        if (BillDesc.BackInbound.getDesc().equals(warehouseInboundRecordDO.getBusinessSingle())) {
            warehouseInboundRecordDO.setFrozen(1);
        }

        boolean isSuccess = warehouseInboundRecordMapper.insert(warehouseInboundRecordDO) > 0;
        ErrorCode code = isSuccess ? ErrorCode.Success : ErrorCode.Failure;

        LogHelper.monitor("businessSingle-----"+warehouseInboundRecordDO.getBusinessSingle());

        //入库成功，库存表里相关记录更新
        if (isSuccess) {
//            String sapCode = companyInfoMapper.getSapCodeByOrgId(orgId);
//            //如果是关键件，则直接将前台传来的批次号和供应商编码保存到条码表中(只针对铲运)
//            if(StringUtils.equals(CompanyUtil.CY_SAP_CODE,sapCode)){
//                if (warehouseInboundRecordDO.getCrucialDevice() != null && warehouseInboundRecordDO.getCrucialDevice() == 1) {
//                    //更新条码表中批次号和供应商编码信息
//                    ErrorCode batchErrorCode = barcodeService.updateSplirIdAndBatchId(warehouseInboundRecordVO.getBarCode(), orgId, warehouseInboundRecordDO.getSplirid(), warehouseInboundRecordDO.getBatchId());
//                    if (batchErrorCode.getCode() != 0) {
//                        throw new Exception("生成入库记录时，更新条码批次号和供应商编码失败");
//                    }
//                }else{
//                    LogHelper.monitor("获取的crucialDevice属性为空：" + JSON.toJSONString(warehouseInboundRecordDO));
//                }
//            }
            ErrorCode barcodeErrorCode = barcodeService.inboundUpdateBarcode(warehouseInboundRecordVO.getBarCode(), BarcodeStatus.Status.InStorage, orgId, userId,warehouseInboundRecordDO.getCreateDate());
            if (barcodeErrorCode.getCode() != 0) {
                throw new Exception("生成入库记录时，更新条码状态失败");
            }
            isSuccess = warehouseInventoryService.saveByInbound(warehouseInboundRecordDO, cost, userId);
            if (!isSuccess) {
                throw new Exception("生成入库记录时，更新库存表失败");
            }
            boolean changeLocationRelation = warehouseInboundRecordVO.isChangeLocationRelation();
            isSuccess = addLocationRelation(warehouseInboundRecordDO, userId,changeLocationRelation);
            if (!isSuccess) {
                throw new Exception("生成入库记录时，新增默认储位失败");
            }
            Map<String, BigDecimal> map = warehouseInboundDetailService.updateByInbound(warehouseInboundRecordDO.getInboundOrder(),
                    warehouseInboundRecordDO.getMaterialNo(), warehouseInboundRecordDO.getAmount(), barcode.getRowNo(), orgId);
            isSuccess = map.get("success").intValue() == 1;
            if (!isSuccess) {
                throw new Exception("生成入库记录时，更新入库主表或入库详情表失败");
            }
            //更新入库业务单据状态
            BigDecimal realAmount = map.get("realAmount");
            Integer singleState = map.get("singleState").intValue();
            Integer totalState = map.get("totalState").intValue();
            Integer rowNo = map.get("rowNo").intValue();
            if (BillDesc.AbnoramlIn.getDesc().equals(warehouseInboundRecordDO.getBusinessSingle())) { //更新非正常入库单
                isSuccess = abnormalInDetailService.updateByInbound(warehouseInboundRecordDO.getBusinessOrder(),
                        warehouseInboundRecordDO.getMaterialNo(), realAmount, singleState, totalState, orgId, warehouseInboundRecordDO.getAmount());
                if (!isSuccess) {  //生成入库记录时，更新非正常入库单和详情状态失败
                    throw new Exception("生成入库记录时，更新非正常入库单和详情状态失败");
                }
            } else if (BillDesc.RegionAllot.getDesc().equals(warehouseInboundRecordDO.getBusinessSingle())) { //更新区域调拨单
                isSuccess = regionAllotDetailService.updateByInbound(warehouseInboundRecordDO.getBusinessOrder(),
                        warehouseInboundRecordDO.getMaterialNo(), realAmount, singleState, totalState, orgId);
                if (!isSuccess) {
                    throw new Exception("生成入库记录时，更新区域调拨单和详情状态失败");
                }
            } else if (BillDesc.AgentAllot.getDesc().equals(warehouseInboundRecordDO.getBusinessSingle())) { //更新代理商间调拨单
                isSuccess = agentAllotDetailService.updateByInbound(warehouseInboundRecordDO.getBusinessOrder(),
                        warehouseInboundRecordDO.getMaterialNo(), realAmount, singleState, totalState, orgId);
                if (!isSuccess) {
                    throw new Exception("生成入库记录时，更新代理商间调拨单和详情状态失败");
                }
            } else if (BillDesc.SaleReverse.getDesc().equals(warehouseInboundRecordDO.getBusinessSingle())) { //更新冲销入库单
                isSuccess = saleReverseDetailService.updateByInbound(warehouseInboundRecordDO.getBusinessOrder(),
                        warehouseInboundRecordDO.getMaterialNo(), realAmount, singleState, totalState, orgId);
                if (!isSuccess) {
                    throw new Exception("生成入库记录时，更新冲销入库单和详情状态失败");
                }

            } else if (BillDesc.SaleReturn.getDesc().equals(warehouseInboundRecordDO.getBusinessSingle())) { //更新退货入库单
                isSuccess = returnInService.updateByInbound(warehouseInboundRecordDO.getBusinessOrder(),
                        warehouseInboundRecordDO.getMaterialNo(), realAmount, singleState, totalState);
                if (!isSuccess) {
                    throw new Exception("生成入库记录时，更新退货入库单和详情状态失败");
                }
            } else if (BillDesc.PurchaseInbound.getDesc().equals(warehouseInboundRecordDO.getBusinessSingle()) || "YNCI".equals(warehouseInboundRecordDO.getBusinessSingle())) { //更新采购入库单
                isSuccess = purchaseInboundService.updateByInbound(warehouseInboundRecordDO.getBusinessOrder(),
                        warehouseInboundRecordDO.getMaterialNo(), realAmount, singleState, totalState, barcode.getRowNo(), orgId);
                if (!isSuccess) {
                    throw new Exception("生成入库记录时，更新采购入库单和详情状态失败");
                }
            } else if (BillDesc.InitialInventory.getDesc().equals(warehouseInboundRecordDO.getBusinessSingle())) { //更新期初入库单
                isSuccess = initialInventoryService.updateByInbound(warehouseInboundRecordDO.getBusinessOrder(),
                        warehouseInboundRecordDO.getMaterialNo(), realAmount, singleState, totalState);
                if (!isSuccess) {
                    throw new Exception("生成入库记录时，更新期初入库单和详情状态失败");
                }
            } else if (BillDesc.MaterialsCode.getDesc().equals(warehouseInboundRecordDO.getBusinessSingle())) { //领料单
                //非关键件，从采购入库单中获取供应商代码
                if (warehouseInboundRecordDO.getCrucialDevice() != null && warehouseInboundRecordDO.getCrucialDevice() == 0) {
                    PurchaseInboundDO purchaseInboundDO = purchaseInboundService.getByPurchaseOrder(warehouseInboundRecordDO.getBusinessOrder(), orgId);
                    if (purchaseInboundDO != null) {
                        //领料单直接取当前企业的SapCode
                        CompanyInfoDO companyInfoDO1 =  companyInfoMapper.item(orgId);
                        if (companyInfoDO1 != null && StringUtils.isNotBlank(companyInfoDO1.getSapCode())) {
                            ErrorCode errorCode = barcodeService.updateSplirIdIfNotExist(warehouseInboundRecordDO.getBarCode(), orgId, companyInfoDO1.getSapCode());
                            if (errorCode.getCode() != 0) {
                                throw new Exception("更新条码表供应商编码失败");
                            }
                        }else{
                            LogHelper.monitor("获取CompanyInfoDO为空或sapCode为空，参数：orgId:" + orgId);
                        }
                    }else{
                        LogHelper.monitor("获取PurchaseInboundDO为空，参数：businessOrder:" + warehouseInboundRecordDO.getBusinessOrder() + ",orgId:" + orgId);
                    }
                }else{
                    LogHelper.monitor("获取的crucialDevice属性为空：" + JSON.toJSONString(warehouseInboundRecordDO));
                }
                isSuccess = materialsScheduleService.updateByInbound(warehouseInboundRecordDO.getBusinessOrder(),
                        warehouseInboundRecordDO.getMaterialNo(), realAmount, singleState, totalState, orgId);
                if (!isSuccess) {
                    throw new Exception("生成入库记录时，更新领料单和详情状态失败");
                }
            } else if (BillDesc.DeliveryInstruction.getDesc().equals(warehouseInboundRecordDO.getBusinessSingle())) { //配送指令入库单
                //非关键件，从采购入库单中获取供应商代码
                if (warehouseInboundRecordDO.getCrucialDevice() != null && warehouseInboundRecordDO.getCrucialDevice() == 0) {
                    PurchaseInboundDO purchaseInboundDO = purchaseInboundService.getByPurchaseOrder(warehouseInboundRecordDO.getBusinessOrder(), orgId);
                    if (purchaseInboundDO != null) {
                        String supplierOrgId = purchaseInboundDO.getSupplierOrgId();
                        CompanySupplierDO companySupplierDO =  companySupplierMapper.itemBySupplierOrgId(orgId, supplierOrgId);
                        if (companySupplierDO != null) {
                            ErrorCode errorCode = barcodeService.updateSplirIdIfNotExist(warehouseInboundRecordDO.getBarCode(), orgId, companySupplierDO.getSupplierCode());
                            if (errorCode.getCode() != 0) {
                                throw new Exception("更新条码表供应商编码失败");
                            }
                        }else{
                            LogHelper.monitor("获取CompanySupplierDO为空，参数：orgId:" + orgId + ",supplierOrgId:" + supplierOrgId);
                        }
                    }else{
                        LogHelper.monitor("获取PurchaseInboundDO为空，参数：businessOrder:" + warehouseInboundRecordDO.getBusinessOrder() + ",orgId:" + orgId);
                    }
                }else{
                    LogHelper.monitor("获取的crucialDevice属性为空：" + JSON.toJSONString(warehouseInboundRecordDO));
                }
                isSuccess = deliveryInstructionDetailService.updateByInbound(warehouseInboundRecordDO.getBusinessOrder(),
                        warehouseInboundRecordDO.getMaterialNo(), realAmount, singleState, totalState, barcode.getRowNo(), orgId);
                if (!isSuccess) {
                    throw new Exception("生成入库记录时，更新配送指令入库单和详情状态失败");
                }
            } else if (BillDesc.ThreeReverse.getDesc().equals(warehouseInboundRecordDO.getBusinessSingle())) { //更新三包冲销入库单
                isSuccess = threeReverseDetailService.updateByInbound(warehouseInboundRecordDO.getBusinessOrder(),
                        warehouseInboundRecordDO.getMaterialNo(), realAmount, singleState, totalState, orgId);
                if (!isSuccess) {
                    throw new Exception("生成入库记录时，更新三包冲销入库单和详情状态失败");
                }
            } else if (BillDesc.BackInbound.getDesc().equals(warehouseInboundRecordDO.getBusinessSingle())) { //更新回购入库单
                isSuccess = backInboundService.updateByInbound(warehouseInboundRecordDO.getBusinessOrder(),
                        warehouseInboundRecordDO.getMaterialNo(), realAmount, singleState, totalState, orgId);
                if (!isSuccess) {
                    throw new Exception("生成入库记录时，更新回购入库单和详情状态失败");
                }
            } else if (BillDesc.SendBill.getDesc().equals(warehouseInboundRecordDO.getBusinessSingle()) || BillDesc.BolSendBill.getDesc().equals(warehouseInboundRecordDO.getBusinessSingle())) { //送货单
                isSuccess = sendBillService.updateByInbound(warehouseInboundRecordDO.getBusinessOrder(),
                        warehouseInboundRecordDO.getMaterialNo(), rowNo, realAmount, singleState, totalState, orgId);
                SendBillDO sendBillDO = sendBillService.findBySendOrder(warehouseInboundRecordDO.getBusinessOrder(), orgId);
                if(sendBillDO == null) {
                    throw new Exception("送货单不存在");
                }
                purchaseInboundService.backPurchaseAmount(warehouseInboundRecordDO.getBusinessOrder(),
                        warehouseInboundRecordDO.getMaterialNo(), realAmount, rowNo, orgId);
                
                if (!isSuccess) {
                    throw new Exception("生成入库记录时，更新送货单和详情状态失败");
                }
            } else if (BillDesc.ReceiptIn.getDesc().equals(warehouseInboundRecordDO.getBusinessSingle())) { //送货单
                isSuccess = receiptInService.updateByInbound(warehouseInboundRecordDO.getBusinessOrder(),
                        warehouseInboundRecordDO.getMaterialNo(), realAmount, singleState, totalState, orgId, barcode);
                if (!isSuccess) {
                    throw new Exception("生成入库记录时，更新运单入库单和详情状态失败");
                }
            } else if (BillDesc.ServiceBorrowIn.getDesc().equals(warehouseInboundRecordDO.getBusinessSingle())) { //服务借用退回
                isSuccess = serviceBorrowInService.updateByInbound(warehouseInboundRecordDO.getBusinessOrder(),
                        warehouseInboundRecordDO.getMaterialNo(), realAmount, singleState, totalState, orgId);
                if (!isSuccess) {
                    throw new Exception("生成入库记录时，更新服务借用退回入库单和详情状态失败");
                }
            }else if (BillDesc.SalesReturnNo.getDesc().equals(warehouseInboundRecordDO.getBusinessSingle())) { //退货单
                isSuccess = agentReturnService.updateByInbound(warehouseInboundRecordDO.getBusinessOrder(),
                        warehouseInboundRecordDO.getMaterialNo(), realAmount, singleState, totalState, orgId);
                if (!isSuccess) {
                    throw new Exception("生成入库记录时，更新退库单和退库零件详情状态失败");
                }
            }else if (BillDesc.BorrowMaterial.getDesc().equals(warehouseInboundRecordDO.getBusinessSingle())){ //借用单
                LogHelper.monitor("更新借用单状态");
                isSuccess = borrowMaterialService.updateByInbound(warehouseInboundRecordDO.getBusinessOrder(),
                        warehouseInboundRecordDO.getMaterialNo(), realAmount, singleState, totalState, orgId);
                if (!isSuccess) {
                    throw new Exception("生成入库记录时，更新借用单状态失败");
                }
            }else if (BillDesc.ZBD.getDesc().equals(warehouseInboundRecordDO.getBusinessSingle())){ //转包单
                LogHelper.monitor("更新转包单状态");
                isSuccess = subcontractingOrderService.updateByInbound(warehouseInboundRecordDO.getBusinessOrder(),
                        warehouseInboundRecordDO.getMaterialNo(), realAmount, singleState, totalState, orgId,
                        warehouseInboundRecordDO.getAmount());
                if (!isSuccess) {  //生成入库记录时，更新非正常入库单和详情状态失败
                    throw new Exception("生成入库记录时，更新转包单状态失败");
                }
            }

//
//            //更新零件标准价
//            Integer isSap = companyInfoDO.getIsSap();
//            BigDecimal oldMateInventory = null;
//            if (null != isSap && 0 == isSap) {
//                //当前零件库存数
//                oldMateInventory = warehouseInventoryService.getInventoryQty(warehouseInboundRecordDO.getMaterialNo(), orgId);
//                oldMateInventory = oldMateInventory == null ? BigDecimal.ZERO : oldMateInventory.subtract(realAmount);
//                updateStandardPrice(orgId, warehouseInboundRecordDO, oldMateInventory, realAmount);
//            }
//            if(oldMateInventory == null) {
//                oldMateInventory = warehouseInventoryService.getInventoryQty(warehouseInboundRecordDO.getMaterialNo(), orgId);
//                oldMateInventory = oldMateInventory == null ? BigDecimal.ZERO : oldMateInventory.subtract(realAmount);
//            }
//            updateParityPrice(orgId, warehouseInboundRecordDO, oldMateInventory, realAmount,barcode.getRowNo());
        }
        return code;
    }

    /**
     * @Author: WangKe
     * @Description: 零件入库时如果没有默认储位则将入库时储位设为默认储位
     *
     * 2021-03-09修改 ： 没有默认储位时新增默认储位，
     * 如果已经存在默认储位，则根据传参needChangeLocationRelation判断是否需要更新默认储位，如果需要更新则判断当前入库储位和默认 储位是否相等，相等则不操作，不想等则进行更新操作
     * @Date: 2018/7/25 0025
     */
    private boolean addLocationRelation(WarehouseInboundRecordDO recordDO, String userId,boolean needChangeLocationRelation) throws Exception {
        MaterialLocationRelationVO condition = new MaterialLocationRelationVO();
        condition.setWarehouseCode(recordDO.getWarehouseCode());
        condition.setMaterialNo(recordDO.getMaterialNo());
        condition.setOrgId(recordDO.getOrgId());
        List<MaterialLocationRelationVO> relationVOList = materialLocationRelationMapper.list(condition);
        if(CollectionUtils.isEmpty(relationVOList)){//新增操作
            MaterialLocationRelationDO relationDO = new MaterialLocationRelationDO();
            relationDO.setId(fastGenClient.textGuid().getValue());
            relationDO.setMaterialNo(recordDO.getMaterialNo());
            relationDO.setWarehouseCode(recordDO.getWarehouseCode());
            relationDO.setAreaCode(recordDO.getAreaCode());
            relationDO.setLocationCode(recordDO.getLocationCode());
            relationDO.setOrgId(recordDO.getOrgId());
            relationDO.setCreateDate(new Date());
            relationDO.setCreateId(userId);
            relationDO.setCreateName(commonService.getUserName(userId));
            return materialLocationRelationMapper.insert(relationDO) > 0;
        }else{//变更默认储位操作
            boolean changeResult = locationRelationChange(userId,  recordDO, needChangeLocationRelation, relationVOList);
            return changeResult;
        }
    }

    /**
     * @Des 更新零件默认储位
     * @Date 2021/3/9 12:09
     * @Author wangzhaoyu
     * @Param [newLocationCode, oldLocationCode, needChangeLocationRelation, oldRelationVOList]
     * @Return void
     */
    public boolean locationRelationChange(String userId,WarehouseInboundRecordDO recordDO,boolean needChangeLocationRelation,List<MaterialLocationRelationVO> oldRelationVOList){
        if(!needChangeLocationRelation){
            return true;
        }
        String newLocationCode = recordDO.getLocationCode();
        if(StringUtils.isEmpty(newLocationCode)){
            return true;
        }
        if(CollectionUtils.isEmpty(oldRelationVOList)){
            return true;
        }
        boolean newLocationCodeExisted = false;
        //判断老的默认储位中是否存在与新传入储位一直的locationCode,如果存在则跳出方法，如果不存在，则把老的数全都删除掉，然后新增一条
        for(MaterialLocationRelationVO materialLocationRelation : oldRelationVOList){
            String locationCode = materialLocationRelation.getLocationCode();
            if(!StringUtils.isEmpty(locationCode) && locationCode.equals(newLocationCode)){
                newLocationCodeExisted = true;
                break;
            }
        }
        if(!newLocationCodeExisted){
            //删除原本存在的默认储位，添加新的默认储位
            for(MaterialLocationRelationVO materialLocationRelation : oldRelationVOList){
                String id = materialLocationRelation.getId();
                materialLocationRelationMapper.deleteByPrimaryKey(id);
            }
            MaterialLocationRelationDO relationDO = new MaterialLocationRelationDO();
            relationDO.setId(fastGenClient.textGuid().getValue());
            relationDO.setMaterialNo(recordDO.getMaterialNo());
            relationDO.setWarehouseCode(recordDO.getWarehouseCode());
            relationDO.setAreaCode(recordDO.getAreaCode());
            relationDO.setLocationCode(recordDO.getLocationCode());
            relationDO.setOrgId(recordDO.getOrgId());
            relationDO.setCreateDate(new Date());
            relationDO.setCreateId(userId);
            relationDO.setCreateName(commonService.getUserName(userId));
            return materialLocationRelationMapper.insert(relationDO) > 0;
        }
        return true;
    }

    /**
     * @Author: WangKe
     * @Description: 无条码化管理的代理商确认收货
     * @Date: 2018/4/4 0004
     */
    @Transactional(rollbackFor = Exception.class)
    public ErrorCode receive(WarehouseInboundAddVO inboundAddVO, String userId, String orgId) throws Exception {
         WarehouseInboundDO inboundDO = warehouseInboundMapper.selectByOrder(inboundAddVO.getHeaderInfo().getBusinessOrder(), orgId);
        if (inboundDO == null) {
            return ErrorCode.IllegalArument;
        }
        if (inboundDO.getStatus() == 2) {
            return ErrorCode.InboundDuplicate;
        }
        List<WarehouseInboundDetailVO> inboundDetailVOList = inboundAddVO.getDetailList();
        if (ListUtil.isNullOrEmpty(inboundDetailVOList)) {
            return ErrorCode.IllegalArument;
        }
        //验证每个零件的储位编码
        Map<String, Map<String, String>> map = new HashMap<>();
        Map<String, String> warehouseMap;
        String warehouseCode = null;
        for (WarehouseInboundDetailVO detailVO : inboundDetailVOList) {
            if (StringUtil.isNullOrEmpty(detailVO.getLocationCode())) {
//                throw new Exception("储位编码不可为空");
                continue;
            }
            if (StringUtil.isNullOrEmpty(detailVO.getAreaCode())
                    || StringUtil.isNullOrEmpty(detailVO.getWarehouseCode())) {
                Map<String, Object> codeMap = warehouseAreaLocationDOMapper.findAllCode(detailVO.getLocationCode(), orgId);
                detailVO.setAreaCode(codeMap.get("AREA_CODE").toString());
                detailVO.setWarehouseCode(codeMap.get("WAREHOUSE_CODE").toString());
            }
            warehouseMap = new HashMap<>();
            warehouseMap.put("LOCATION_CODE", detailVO.getLocationCode());
            warehouseMap.put("AREA_CODE", detailVO.getAreaCode());
            warehouseMap.put("WAREHOUSE_CODE", detailVO.getWarehouseCode());
            map.put(detailVO.getMaterialNo(), warehouseMap);
            warehouseCode = detailVO.getWarehouseCode();

        }

        List<WarehouseInboundDetailDO> inboundDetailDOList = warehouseInboundDetailMapper.findByBusinessOrder(inboundDO.getBusinessOrder(), orgId);
        if (ListUtil.isNullOrEmpty(inboundDetailDOList)) {
            return ErrorCode.IllegalArument;
        }

        // 校验仓库是否允许非条码化入库
        if (StringUtils.isBlank(warehouseCode)){
            return ErrorCode.WarehouseLocationCodeError;
        }

        CompanyInfoDO companyInfoDO = companyInfoMapper.item(orgId);
        Integer isBarcode = companyInfoDO.getIsBarcode();
        int countIsBarCode = warehouseDOMapper.countIsBarCode(orgId, warehouseCode);

        //非条码化且仓库允许条码化返回错误信息
//        if ((null == isBarcode || 0 == isBarcode) && countIsBarCode > 0){
//            return ErrorCode.BarcodeWarehouseDoesNotAllowBarcodeStorage;
//        }
        if (countIsBarCode > 0){
            return ErrorCode.BarcodeWarehouseDoesNotAllowBarcodeStorage;
        }

        Integer isSap = companyInfoDO.getIsSap();
        boolean success;
        WarehouseInboundRecordDO warehouseInboundRecordDO;
        for (WarehouseInboundDetailDO inboundDetailDO : inboundDetailDOList) {
            if (inboundDetailDO.getStatus() == 3 || inboundDetailDO.getStatus() == 2) {
                continue;
            }
            //插入入库记录
            warehouseInboundRecordDO = new WarehouseInboundRecordDO();
            BeanUtils.copyProperties(inboundDetailDO, warehouseInboundRecordDO);

            warehouseMap = map.get(inboundDetailDO.getMaterialNo());
            if (warehouseMap == null || warehouseMap.get("WAREHOUSE_CODE") == null || warehouseMap.get("AREA_CODE") == null) {
                throw new Exception("储位编码错误");
            }
            warehouseInboundRecordDO.setLocationCode(warehouseMap.get("LOCATION_CODE"));
            warehouseInboundRecordDO.setAreaCode(warehouseMap.get("AREA_CODE"));
            warehouseInboundRecordDO.setWarehouseCode(warehouseMap.get("WAREHOUSE_CODE"));
            warehouseInboundRecordDO.setRealAmount(inboundDetailDO.getAmount());
            warehouseInboundRecordDO.setOrgId(orgId);
            warehouseInboundRecordDO.setCreaterId(userId);
            warehouseInboundRecordDO.setCreaterName(commonService.getUserName(userId));
            warehouseInboundRecordDO.setCreateDate(new Date());
            warehouseInboundRecordDO.setFrozen(0);
            warehouseInboundRecordDO.setInboundType(1);
            warehouseInboundRecordDO.setBarCode("0");

            success = warehouseInboundRecordMapper.insert(warehouseInboundRecordDO) > 0;
            if (!success) {
                throw new Exception("生成入库记录失败");
            }
            //当前零件库存数
            BigDecimal oldMateInventory = warehouseInventoryService.getInventoryQty(warehouseInboundRecordDO.getMaterialNo(), orgId);
            //更新库存
            success = warehouseInventoryService.updateByInboundWithNoBarcode(warehouseInboundRecordDO, userId, orgId);
            if (!success) {
                throw new Exception("更新库存失败");
            }

            //更新入库事物单状态
            success = warehouseInboundService.updateStateNoBarcode(warehouseInboundRecordDO.getBusinessOrder(), warehouseInboundRecordDO.getMaterialNo(),
                    2, warehouseInboundRecordDO.getOrgId());
            if (!success) {
                throw new Exception("更新入库事物单状态失败");
            }

            success = addLocationRelation(warehouseInboundRecordDO, userId,false);
            if (!success) {
                throw new Exception("生成入库记录时，新增默认储位失败");
            }

            //更新入库业务单据状态
            BigDecimal realAmount = warehouseInboundRecordDO.getRealAmount();
            Integer singleState = 2;
            Integer totalState = 2;
            if (BillDesc.AbnoramlIn.getDesc().equals(warehouseInboundRecordDO.getBusinessSingle())) { //更新非正常入库单
                success = abnormalInDetailService.updateByInbound(warehouseInboundRecordDO.getBusinessOrder(),
                        warehouseInboundRecordDO.getMaterialNo(), realAmount, singleState, totalState, orgId, null);
                if (!success) {  //生成入库记录时，更新非正常入库单和详情状态失败
                    throw new Exception("生成入库记录时，更新非正常入库单和详情状态失败");
                }
            } else if (BillDesc.RegionAllot.getDesc().equals(warehouseInboundRecordDO.getBusinessSingle())) { //更新区域调拨单
                success = regionAllotDetailService.updateByInbound(warehouseInboundRecordDO.getBusinessOrder(),
                        warehouseInboundRecordDO.getMaterialNo(), realAmount, singleState, totalState, orgId);
                if (!success) {
                    throw new Exception("生成入库记录时，更新区域调拨单和详情状态失败");
                }
            } else if (BillDesc.AgentAllot.getDesc().equals(warehouseInboundRecordDO.getBusinessSingle())) { //更新代理商间调拨单
                success = agentAllotDetailService.updateByInbound(warehouseInboundRecordDO.getBusinessOrder(),
                        warehouseInboundRecordDO.getMaterialNo(), realAmount, singleState, totalState, orgId);
                if (!success) {
                    throw new Exception("生成入库记录时，更新代理商间调拨单和详情状态失败");
                }
            } else if (BillDesc.SaleReverse.getDesc().equals(warehouseInboundRecordDO.getBusinessSingle())) { //更新冲销入库单
                success = saleReverseDetailService.updateByInbound(warehouseInboundRecordDO.getBusinessOrder(),
                        warehouseInboundRecordDO.getMaterialNo(), realAmount, singleState, totalState, orgId);
                if (!success) {
                    throw new Exception("生成入库记录时，更新冲销入库单和详情状态失败");
                }

            } else if (BillDesc.SaleReturn.getDesc().equals(warehouseInboundRecordDO.getBusinessSingle())) { //更新退货入库单
                success = returnInService.updateByInbound(warehouseInboundRecordDO.getBusinessOrder(),
                        warehouseInboundRecordDO.getMaterialNo(), realAmount, singleState, totalState);
                if (!success) {
                    throw new Exception("生成入库记录时，更新退货入库单和详情状态失败");
                }
            } else if (BillDesc.PurchaseInbound.getDesc().equals(warehouseInboundRecordDO.getBusinessSingle())) { //更新采购入库单
                success = purchaseInboundService.updateByInbound(warehouseInboundRecordDO.getBusinessOrder(),
                        warehouseInboundRecordDO.getMaterialNo(), realAmount, singleState, totalState, null, orgId);
                if (!success) {
                    throw new Exception("生成入库记录时，更新采购入库单和详情状态失败");
                }
            } else if (BillDesc.InitialInventory.getDesc().equals(warehouseInboundRecordDO.getBusinessSingle())) { //更新采购入库单
                success = initialInventoryService.updateByInbound(warehouseInboundRecordDO.getBusinessOrder(),
                        warehouseInboundRecordDO.getMaterialNo(), realAmount, singleState, totalState);
                if (!success) {
                    throw new Exception("生成入库记录时，更新期初入库单和详情状态失败");
                }
            } else if (BillDesc.ReceiptIn.getDesc().equals(warehouseInboundRecordDO.getBusinessSingle())) { //更新运单入库单
                success = receiptInService.updateByInbound(warehouseInboundRecordDO.getBusinessOrder(),
                        warehouseInboundRecordDO.getMaterialNo(), realAmount, singleState, totalState, "", null);
                if (!success) {
                    throw new Exception("生成入库记录时，更新运单入库单和详情状态失败");
                }
            } else if (BillDesc.SendBill.getDesc().equals(warehouseInboundRecordDO.getBusinessSingle())) { //更新送货单入库单
                success = sendBillService.updateByInbound(warehouseInboundRecordDO.getBusinessOrder(),
                        warehouseInboundRecordDO.getMaterialNo(), inboundDetailDO.getRowNo(), realAmount, singleState, totalState, orgId);
                if (!success) {
                    throw new Exception("生成入库记录时，更新送货单入库单和详情状态失败");
                }
            } else if (BillDesc.ServiceBorrowIn.getDesc().equals(warehouseInboundRecordDO.getBusinessSingle())) { //服务借用退回
                success = serviceBorrowInService.updateByInbound(warehouseInboundRecordDO.getBusinessOrder(),
                        warehouseInboundRecordDO.getMaterialNo(), realAmount, singleState, totalState, orgId);
                if (!success) {
                    throw new Exception("生成入库记录时，更新服务借用退回入库单和详情状态失败");
                }
            }else if(BillDesc.SalesReturnNo.getDesc().equals(warehouseInboundRecordDO.getBusinessSingle())) { //退货单
                success = agentReturnService.updateByInbound(warehouseInboundRecordDO.getBusinessOrder(),
                        warehouseInboundRecordDO.getMaterialNo(), realAmount, singleState, totalState, orgId);
                if (!success) {
                    throw new Exception("生成入库记录时，更新退库单和退库零件详情状态失败");
                }
            }else if (BillDesc.MaterialsCode.getDesc().equals(warehouseInboundRecordDO.getBusinessSingle())) { //领料单
                success = materialsScheduleService.updateByInbound(warehouseInboundRecordDO.getBusinessOrder(),
                        warehouseInboundRecordDO.getMaterialNo(), realAmount, singleState, totalState, orgId);
                if (!success) {
                    throw new Exception("生成入库记录时，更新领料单和详情状态失败");
                }
            }

            if (null != isSap && 0 == isSap) {
                updateStandardPrice(orgId, warehouseInboundRecordDO, oldMateInventory, realAmount);
            }
            
            updateParityPrice(orgId, warehouseInboundRecordDO, oldMateInventory, realAmount,null);
        }
        return ErrorCode.Success;
    }

    /**
     * 修改零件标准价格
     *
     * @param orgId
     * @param warehouseInboundRecordDO
     * @param oldMateInventory
     * @param realAmount
     * @throws Exception
     */
    private void updateStandardPrice(String orgId, WarehouseInboundRecordDO warehouseInboundRecordDO, BigDecimal oldMateInventory, BigDecimal realAmount) throws Exception {
        if (BillDesc.AbnoramlIn.getDesc().equals(warehouseInboundRecordDO.getBusinessSingle())) { //更新非正常入库单

            AbnormalInDetailDO abnormalInDetailDO = abnormalInDetailService.getAbnormalInDetailDO(warehouseInboundRecordDO.getBusinessOrder(),
                    warehouseInboundRecordDO.getMaterialNo(), orgId);
            if (null == abnormalInDetailDO) {
                throw new Exception("生成入库记录时，更新零件标准价格失败");
            }
            BigDecimal price = abnormalInDetailDO.getPrice();
            updateStandardPriceLogic(orgId, warehouseInboundRecordDO, oldMateInventory, realAmount, price);

        } else if (BillDesc.AgentAllot.getDesc().equals(warehouseInboundRecordDO.getBusinessSingle())) { //更新代理商间调拨单

            AgentAllotDetailDO agentAllotDetailDO = agentAllotDetailService.getAgentAllotDetailDO(warehouseInboundRecordDO.getBusinessOrder(),
                    warehouseInboundRecordDO.getMaterialNo(), orgId);
            if (null == agentAllotDetailDO) {
                throw new Exception("生成入库记录时，更新零件标准价格失败");
            }

            BigDecimal price = agentAllotDetailDO.getRealPrice();
            updateStandardPriceLogic(orgId, warehouseInboundRecordDO, oldMateInventory, realAmount, price);
        } else if (BillDesc.SaleReturn.getDesc().equals(warehouseInboundRecordDO.getBusinessSingle())) { //更新退货入库单

            SalesReturnInDetailDO salesReturnInDetailDO = returnInService.getSalesReturnInDetailDO(warehouseInboundRecordDO.getBusinessOrder(),
                    warehouseInboundRecordDO.getMaterialNo());
            if (null == salesReturnInDetailDO) {
                throw new Exception("生成入库记录时，更新零件标准价格失败");
            }

            BigDecimal price = salesReturnInDetailDO.getPrice();
            updateStandardPriceLogic(orgId, warehouseInboundRecordDO, oldMateInventory, realAmount, price);

        } else if (BillDesc.PurchaseInbound.getDesc().equals(warehouseInboundRecordDO.getBusinessSingle())) { //更新采购入库单

            PurchaseInboundDetailDO purchaseInboundDetailDO = purchaseInboundService.getPurchaseInboundDetailDO(warehouseInboundRecordDO.getBusinessOrder(),
                    warehouseInboundRecordDO.getMaterialNo(), null, orgId);
            if (null == purchaseInboundDetailDO) {
                throw new Exception("生成入库记录时，更新零件标准价格失败");
            }

            BigDecimal price = purchaseInboundDetailDO.getPrice();
            updateStandardPriceLogic(orgId, warehouseInboundRecordDO, oldMateInventory, realAmount, price);

        } else if (BillDesc.InitialInventory.getDesc().equals(warehouseInboundRecordDO.getBusinessSingle())) { //更新初其入库单

            InitialInventoryDetailDO initialInventoryDetailDO = initialInventoryService.getInitialInventoryDetailDO(warehouseInboundRecordDO.getBusinessOrder(),
                    warehouseInboundRecordDO.getMaterialNo());
            if (null == initialInventoryDetailDO) {
                throw new Exception("生成入库记录时，更新零件标准价格失败");
            }

            BigDecimal price = initialInventoryDetailDO.getUnitPrice();
            updateStandardPriceLogic(orgId, warehouseInboundRecordDO, oldMateInventory, realAmount, price);

        } else if (BillDesc.ReceiptIn.getDesc().equals(warehouseInboundRecordDO.getBusinessSingle())) { //更新运单入库单

            BigDecimal price = receiptInService.getPrice(warehouseInboundRecordDO.getBusinessOrder(),
                    warehouseInboundRecordDO.getMaterialNo());
            updateStandardPriceLogic(orgId, warehouseInboundRecordDO, oldMateInventory, realAmount, price);

        } else if (BillDesc.SendBill.getDesc().equals(warehouseInboundRecordDO.getBusinessSingle())) { //更新送货单入库单

            BigDecimal price = sendBillService.getPrice(warehouseInboundRecordDO.getBusinessOrder(),
                    warehouseInboundRecordDO.getMaterialNo(), orgId);
            updateStandardPriceLogic(orgId, warehouseInboundRecordDO, oldMateInventory, realAmount, price);

        }
    }
    
    /**
     * 更新平价
     * @param orgId
     * @param warehouseInboundRecordDO
     * @param oldMateInventory
     * @param realAmount
     * @throws Exception
     */
    private void updateParityPrice(String orgId, WarehouseInboundRecordDO warehouseInboundRecordDO, BigDecimal oldMateInventory, BigDecimal realAmount,Integer rowNo) throws Exception {
        if (BillDesc.AbnoramlIn.getDesc().equals(warehouseInboundRecordDO.getBusinessSingle())) { //更新非正常入库单

            AbnormalInDetailDO abnormalInDetailDO = abnormalInDetailService.getAbnormalInDetailDO(warehouseInboundRecordDO.getBusinessOrder(),
                    warehouseInboundRecordDO.getMaterialNo(), orgId);
            if (null == abnormalInDetailDO) {
                throw new Exception("生成入库记录时，更新零件标准价格失败");
            }
            BigDecimal price = abnormalInDetailDO.getPrice();
            updateParityPriceLogic(orgId, warehouseInboundRecordDO, oldMateInventory, realAmount, price);

        } else if (BillDesc.AgentAllot.getDesc().equals(warehouseInboundRecordDO.getBusinessSingle())) { //更新代理商间调拨单

            AgentAllotDetailDO agentAllotDetailDO = agentAllotDetailService.getAgentAllotDetailDO(warehouseInboundRecordDO.getBusinessOrder(),
                    warehouseInboundRecordDO.getMaterialNo(), orgId);
            if (null == agentAllotDetailDO) {
                throw new Exception("生成入库记录时，更新零件标准价格失败");
            }

            BigDecimal price = agentAllotDetailDO.getRealPrice();
            updateParityPriceLogic(orgId, warehouseInboundRecordDO, oldMateInventory, realAmount, price);
        } else if (BillDesc.SaleReturn.getDesc().equals(warehouseInboundRecordDO.getBusinessSingle())) { //更新退货入库单

            SalesReturnInDetailDO salesReturnInDetailDO = returnInService.getSalesReturnInDetailDO(warehouseInboundRecordDO.getBusinessOrder(),
                    warehouseInboundRecordDO.getMaterialNo());
            if (null == salesReturnInDetailDO) {
                throw new Exception("生成入库记录时，更新零件标准价格失败");
            }

            BigDecimal price = salesReturnInDetailDO.getPrice();
            updateParityPriceLogic(orgId, warehouseInboundRecordDO, oldMateInventory, realAmount, price);

        } else if (BillDesc.PurchaseInbound.getDesc().equals(warehouseInboundRecordDO.getBusinessSingle())) { //更新采购入库单

            PurchaseInboundDetailDO purchaseInboundDetailDO = purchaseInboundService.getPurchaseInboundDetailDO(warehouseInboundRecordDO.getBusinessOrder(),
                    warehouseInboundRecordDO.getMaterialNo(), rowNo, orgId);
            if (null == purchaseInboundDetailDO) {
                throw new Exception("生成入库记录时，更新零件标准价格失败");
            }

            BigDecimal price = purchaseInboundDetailDO.getPrice();
            updateParityPriceLogic(orgId, warehouseInboundRecordDO, oldMateInventory, realAmount, price);

        } else if (BillDesc.InitialInventory.getDesc().equals(warehouseInboundRecordDO.getBusinessSingle())) { //更新初其入库单

            InitialInventoryDetailDO initialInventoryDetailDO = initialInventoryService.getInitialInventoryDetailDO(warehouseInboundRecordDO.getBusinessOrder(),
                    warehouseInboundRecordDO.getMaterialNo());
            if (null == initialInventoryDetailDO) {
                throw new Exception("生成入库记录时，更新零件标准价格失败");
            }

            BigDecimal price = initialInventoryDetailDO.getUnitPrice();
            updateParityPriceLogic(orgId, warehouseInboundRecordDO, oldMateInventory, realAmount, price);

        } else if (BillDesc.ReceiptIn.getDesc().equals(warehouseInboundRecordDO.getBusinessSingle())) { //更新运单入库单

            BigDecimal price = receiptInService.getPrice(warehouseInboundRecordDO.getBusinessOrder(),
                    warehouseInboundRecordDO.getMaterialNo());
            updateParityPriceLogic(orgId, warehouseInboundRecordDO, oldMateInventory, realAmount, price);

        } else if (BillDesc.SendBill.getDesc().equals(warehouseInboundRecordDO.getBusinessSingle())) { //更新送货单入库单

            BigDecimal price = sendBillService.getPrice(warehouseInboundRecordDO.getBusinessOrder(),
                    warehouseInboundRecordDO.getMaterialNo(), orgId);
            updateParityPriceLogic(orgId, warehouseInboundRecordDO, oldMateInventory, realAmount, price);

        }
    }

    private void updateStandardPriceLogic(String orgId, WarehouseInboundRecordDO warehouseInboundRecordDO, BigDecimal oldMateInventory, BigDecimal realAmount, BigDecimal price) throws Exception {
        if (null == price || null == realAmount || price.compareTo(BigDecimal.ZERO) == 0) {
            return;
        }
        String materialNo = warehouseInboundRecordDO.getMaterialNo();
        oldMateInventory = oldMateInventory == null ? BigDecimal.ZERO : oldMateInventory;
        BigDecimal totalInventoryQty = realAmount.add(oldMateInventory);//库存总数
        if (totalInventoryQty == null || totalInventoryQty.compareTo(BigDecimal.ZERO) == 0){
            return;
        }
        BigDecimal thisTotalPrice = price.multiply(realAmount);//零件小计价格
        MaterialsVO materialsVO = materialsService.itemByNo(materialNo, orgId);
        if (null == materialsVO) {
            throw new Exception("生成入库记录时,零件信息不存在");
        }
        if (null == materialsVO.getStandardPrice()) {
            materialsVO.setStandardPrice(BigDecimal.ZERO);
        }
        BigDecimal standardPrice = materialsVO.getStandardPrice();
        BigDecimal oldTotalPrice = standardPrice.multiply(oldMateInventory);
        BigDecimal totalPrice = oldTotalPrice.add(thisTotalPrice);
        BigDecimal newStandardPrice = totalPrice.divide(totalInventoryQty, 2, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100));
        //更新零件的成本价
        ErrorCode errorCode = materialsService.updateStandardPrice(materialNo, orgId, newStandardPrice);
        if (ErrorCode.Success != errorCode) {
            throw new Exception("生成入库记录时,修改零件标准价失败");
        }
    }
    
    private void updateParityPriceLogic(String orgId, WarehouseInboundRecordDO warehouseInboundRecordDO, BigDecimal oldMateInventory, BigDecimal realAmount, BigDecimal price) throws Exception {
        if (null == price || null == realAmount || price.compareTo(BigDecimal.ZERO) == 0) {
            return;
        }
        String materialNo = warehouseInboundRecordDO.getMaterialNo();
        oldMateInventory = oldMateInventory == null ? BigDecimal.ZERO : oldMateInventory;
        BigDecimal totalInventoryQty = realAmount.add(oldMateInventory);//库存总数
        if (totalInventoryQty == null || totalInventoryQty.compareTo(BigDecimal.ZERO) == 0) {
            return;
        }
        BigDecimal thisTotalPrice = price.multiply(realAmount);//零件小计价格
        MaterialsVO materialsVO = materialsService.itemByNo(materialNo, orgId);
        if (null == materialsVO) {
            throw new Exception("生成入库记录时,零件信息不存在");
        }
        if (null == materialsVO.getStandardPrice()) {
            materialsVO.setStandardPrice(BigDecimal.ZERO);
        }
        BigDecimal parityPrice = materialsVO.getParityPrice();
        if (parityPrice == null) {
            parityPrice = BigDecimal.ZERO;
        }
        BigDecimal oldTotalPrice = parityPrice.multiply(oldMateInventory);
        BigDecimal totalPrice = oldTotalPrice.add(thisTotalPrice);
        BigDecimal newParityPrice = totalPrice.divide(totalInventoryQty, 2, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100));
        //更新零件的成本价
        ErrorCode errorCode = materialsService.updateParityPrice(materialNo, orgId, newParityPrice);
        if (ErrorCode.Success != errorCode) {
            throw new Exception("生成入库记录时,修改零件标准价失败");
        }
    }


    /**
     * @Author: WangKe
     * @Description: 根据入库单号查找入库记录列表
     * @Date: 2018/1/19 0019
     */
    public List<WarehouseInboundRecordDO> findByInboundOrder(String inboundOrder, String orgId) {
        if (inboundOrder == null) {
            return new ArrayList<WarehouseInboundRecordDO>();
        }
        return warehouseInboundRecordMapper.findByInboundOrder(inboundOrder, orgId);
    }

    /**
     * @Author: WangKe
     * @Description: 根据入库单号删除入库记录
     * @Date: 2018/1/23 0023
     */
    public ErrorCode deleteByInboundOrder(String inboundOrder, String orgId) {
        int i = warehouseInboundRecordMapper.deleteByInboundOrder(inboundOrder, orgId);
        return i > 0 ? ErrorCode.Success : ErrorCode.WarehouseIdError;
    }

    /**
     * @Author: WangKe
     * @Description: 根据入库单号删除入库详情记录
     * @Date: 2018/1/26 0026
     */
    public ErrorCode deleteByInboundOrderList(List<String> orderList, String orgId) {
        int i = warehouseInboundRecordMapper.removeByInOrderList(orderList, orgId);
        return i > 0 ? ErrorCode.Success : ErrorCode.WarehouseIdError;
    }

    /**
     * @Author: WangKe
     * @Description: 根据主键删除记录
     * @Date: 15:39 2018/1/17 0017
     */
    public ErrorCode delete(String id) {
        int i = warehouseInboundRecordMapper.deleteByPrimaryKey(id);
        return i > 0 ? ErrorCode.Success : ErrorCode.WarehouseIdError;
    }

    /**
     * @Author: WangKe
     * @Description: 根据主键列表删除记录
     * @Date: 2018/1/26 0026
     */
    public ErrorCode remove(List<String> ids) {
        return warehouseInboundRecordMapper.remove(ids) > 0 ? ErrorCode.Success : ErrorCode.WarehouseIdError;
    }

    /**
     * @Author: WangKe
     * @Description: 查询入库记录列表
     * @Date: 17:04 2018/1/17 0017
     */
    public PageCommonVO list(SearchCommonVO<WarehouseInboundRecordVO> condition) {
        PageCommonVO<WarehouseInboundRecordVO> pageCommonVO = new PageCommonVO();
        PageHelperPlus.orderBy("create_date desc");
        PageHelperPlus.startPage(condition.getPageNum(), condition.getPageSize());
        if (!StringUtil.isNullOrEmpty(condition.getFilters().getLocationCode())) {
            String locationCode = condition.getFilters().getLocationCode();
            if (locationCode.toCharArray()[0] == '\uFEFF') {
                locationCode = locationCode.substring(1);
                condition.getFilters().setLocationCode(locationCode);
            }
        }
        List<WarehouseInboundRecordDO> doList = warehouseInboundRecordMapper.list(condition.getFilters());
        List<WarehouseInboundRecordVO> voList = new ArrayList<WarehouseInboundRecordVO>();
        for (WarehouseInboundRecordDO entity : doList) {
            WarehouseInboundRecordVO model = new WarehouseInboundRecordVO();
            BeanUtils.copyProperties(entity, model);
            voList.add(model);
        }
        pageCommonVO.setPageInfo(new PageInfo(doList));
        pageCommonVO.setPageInfoList(voList);
        return pageCommonVO;
    }

    /**
     * @Author: WangKe
     * @Description: 导出入库记录列表
     * @Date: 2018/2/7 0007
     */
    public void export(List<String> ids) throws Exception {
        invokeExport(warehouseInboundRecordMapper.findByIds(ids));
    }

    /**
     * @Author: WangKe
     * @Description: 导出全部入库记录列表
     * @Date: 2018/2/7 0007
     */
    public void exportAll(WarehouseInboundRecordVO condition) throws Exception {
        Integer count = warehouseInboundRecordMapper.findCountForExportAll(condition);
        List<WarehouseInboundRecordDO> dataList = new ArrayList<>();
        int times = count / 500 + 1;
        for (int i = 0; i < times; i++) {
            PageHelperPlus.startPage(i + 1, 500, "create_date desc");
            dataList.addAll(warehouseInboundRecordMapper.list(condition));
        }
        invokeExport(dataList);
    }

    /**
     * @Author: WangKe
     * @Description: 导出入库记录列表
     * @Date: 2018/2/7 0007
     */
    private void invokeExport(List<WarehouseInboundRecordDO> doList) throws Exception {
        if (ListUtil.isNullOrEmpty(doList)) {
            return;
        }
        String title = "入库记录数据导出";
        String[] rowsName = new String[]{"序号", "条码", "入库单号", "业务类别", "业务单号", "备注信息",
                "零件编码", "零件名称", "零件类型", "仓库编码", "仓库编码", "储位编码", "单位", "入库数量",
                "是否冻结", "创建人", "创建日期"};
        List<Object[]> dataList = new ArrayList<Object[]>();
        Object[] objs;
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        for (int i = 0; i < doList.size(); i++) {
            WarehouseInboundRecordDO inboundRecordDO = doList.get(i);
            objs = new Object[rowsName.length];
            objs[0] = i + 1;
            objs[1] = inboundRecordDO.getBarCode();
            objs[2] = inboundRecordDO.getInboundOrder();
            objs[3] = inboundRecordDO.getBusinessSingle();
            objs[4] = inboundRecordDO.getBusinessOrder();
            objs[5] = inboundRecordDO.getNote();
            objs[6] = inboundRecordDO.getMaterialNo();
            objs[7] = inboundRecordDO.getMaterialName();
            objs[8] = inboundRecordDO.getMaterialType();
            objs[9] = inboundRecordDO.getWarehouseCode();
            objs[10] = inboundRecordDO.getAreaCode();
            objs[11] = inboundRecordDO.getLocationCode();
            objs[12] = inboundRecordDO.getUnit();
            objs[13] = inboundRecordDO.getAmount();
            objs[14] = inboundRecordDO.getFrozen() == 0 ? "否" : "是";
            objs[15] = inboundRecordDO.getCreaterName();
            objs[16] = sdf.format(inboundRecordDO.getCreateDate());
            dataList.add(objs);
        }
        ExportUtil exportUtil = new ExportUtil(title, rowsName, dataList);
        exportUtil.export(response);
    }

    /**
     * @Author: WangKe
     * @Description: 获取入库业务单已入库和未入库的数量
     * @Date: 2018/3/14 0014
     */
    public InOutNumVO findAlreadyInboundNum(String businessOrder, String orgId) {
        //如果是送货单
        if (businessOrder.startsWith(BillDesc.SendBill.getDesc())) {
            return this.findAlreadyInboundNumSH(businessOrder, orgId);
        }
        List<WarehouseInboundDetailDO> detailDOList = warehouseInboundDetailMapper.findByBusinessOrder(businessOrder, orgId);
        if (ListUtil.isNullOrEmpty(detailDOList)) {
            return new InOutNumVO();
        }
        Integer alreadyNum = 0;
        Integer notAlreadyNum = 0;
        String rowNo;
        Map<String, BigDecimal> map = new HashMap<>();
        List<BarcodeManageDO> barcodeManageDOList = barcodeManageMapper.findAlreadyInbound(businessOrder, orgId);
        if (CollectionUtils.isNotEmpty(barcodeManageDOList)) {
            for (BarcodeManageDO barcodeManageDO : barcodeManageDOList) {
                rowNo = barcodeManageDO.getRowNo() == null ? "_0" : "_" + barcodeManageDO.getRowNo();
                map.put(barcodeManageDO.getMaterialsNo() + rowNo, barcodeManageDO.getCurrentQty());
            }
        }
        for (WarehouseInboundDetailDO detailDO : detailDOList) {
            rowNo = detailDO.getRowNo() == null ? "_0" : "_" + detailDO.getRowNo();
            if ((map.containsKey(detailDO.getMaterialNo() + rowNo) && (detailDO.getAmount().compareTo(map.get(detailDO.getMaterialNo() + rowNo)) == 0)) || detailDO.getStatus() == 3 || detailDO.getStatus() == 2) {
                alreadyNum += 1;
            } else {
                notAlreadyNum += 1;
            }
        }
        return new InOutNumVO(alreadyNum, notAlreadyNum);
    }

    /**
     * @Author: WangKe
     * @Description: 获取入库业务单已入库和未入库的列表
     * @Date: 2018/3/14 0014
     */
    public List<WarehouseInboundDetailDO> findAlreadyInboundList(String businessOrder, Integer state, String orgId) {
        //如果是送货单
        if (businessOrder.startsWith(BillDesc.SendBill.getDesc())) {
            return this.findAlreadyInboundListSH(businessOrder, state, orgId);
        }
        List<WarehouseInboundDetailDO> alreadyList = new ArrayList<>();
        List<WarehouseInboundDetailDO> notAlreadyList = new ArrayList<>();
        List<WarehouseInboundDetailDO> detailDOList = warehouseInboundDetailMapper.findByBusinessOrder(businessOrder, orgId);
        if (ListUtil.isNullOrEmpty(detailDOList)) {
            return alreadyList;
        }
        String rowNo;
        Map<String, BigDecimal> map = new HashMap<>();
        List<BarcodeManageDO> barcodeManageDOList = barcodeManageMapper.findAlreadyInbound(businessOrder, orgId);
        if (CollectionUtils.isNotEmpty(barcodeManageDOList)) {
            for (BarcodeManageDO barcodeManageDO : barcodeManageDOList) {
                rowNo = barcodeManageDO.getRowNo() == null ? "_0" : "_" + barcodeManageDO.getRowNo();
                map.put(barcodeManageDO.getMaterialsNo() + rowNo, barcodeManageDO.getCurrentQty());
            }
        }
        for (WarehouseInboundDetailDO detailDO : detailDOList) {
            rowNo = detailDO.getRowNo() == null ? "_0" : "_" + detailDO.getRowNo();
            if ((map.containsKey(detailDO.getMaterialNo() + rowNo) && (detailDO.getAmount().compareTo(map.get(detailDO.getMaterialNo() + rowNo)) == 0)) || detailDO.getStatus() == 3 || detailDO.getStatus() == 2) {
                alreadyList.add(detailDO);
            } else {
                notAlreadyList.add(detailDO);
            }
        }
        if (state == 1) {
            return alreadyList;
        } else {
            return notAlreadyList;
        }
    }

    private InOutNumVO findAlreadyInboundNumSH(String businessOrder, String orgId) {
        List<WarehouseInboundDetailDO> detailDOList = warehouseInboundDetailMapper.findByBusinessOrder(businessOrder, orgId);
        if (ListUtil.isNullOrEmpty(detailDOList)) {
            return new InOutNumVO();
        }
        Integer alreadyNum = 0;
        Integer notAlreadyNum = 0;
        Map<String, BigDecimal> map = new HashMap<>();
        List<BarcodeManageDO> barcodeManageDOList = barcodeManageMapper.findAlreadyInbound(businessOrder, orgId);
        if (CollectionUtils.isNotEmpty(barcodeManageDOList)) {
            for (BarcodeManageDO barcodeManageDO : barcodeManageDOList) {
                map.put(barcodeManageDO.getMaterialsNo(), barcodeManageDO.getCurrentQty());
            }
        }
        for (WarehouseInboundDetailDO detailDO : detailDOList) {
            if ((map.containsKey(detailDO.getMaterialNo()) && (detailDO.getAmount().compareTo(map.get(detailDO.getMaterialNo())) == 0)) || detailDO.getStatus() == 3 || detailDO.getStatus() == 2) {
                alreadyNum += 1;
                map.remove(detailDO.getMaterialNo());
            } else {
                notAlreadyNum += 1;
            }
        }
        return new InOutNumVO(alreadyNum, notAlreadyNum);
    }

    private List<WarehouseInboundDetailDO> findAlreadyInboundListSH(String businessOrder, Integer state, String orgId) {
        List<WarehouseInboundDetailDO> alreadyList = new ArrayList<>();
        List<WarehouseInboundDetailDO> notAlreadyList = new ArrayList<>();
        List<WarehouseInboundDetailDO> detailDOList = warehouseInboundDetailMapper.findByBusinessOrder(businessOrder, orgId);
        if (ListUtil.isNullOrEmpty(detailDOList)) {
            return alreadyList;
        }
        Map<String, BigDecimal> map = new HashMap<>();
        List<BarcodeManageDO> barcodeManageDOList = barcodeManageMapper.findAlreadyInbound(businessOrder, orgId);
        if (CollectionUtils.isNotEmpty(barcodeManageDOList)) {
            for (BarcodeManageDO barcodeManageDO : barcodeManageDOList) {
                map.put(barcodeManageDO.getMaterialsNo(), barcodeManageDO.getCurrentQty());
            }
        }
        for (WarehouseInboundDetailDO detailDO : detailDOList) {
            if ((map.containsKey(detailDO.getMaterialNo()) && (detailDO.getAmount().compareTo(map.get(detailDO.getMaterialNo())) == 0)) || detailDO.getStatus() == 3 || detailDO.getStatus() == 2) {
                alreadyList.add(detailDO);
                map.remove(detailDO.getMaterialNo());
            } else {
                notAlreadyList.add(detailDO);
            }
        }
        if (state == 1) {
            return alreadyList;
        } else {
            return notAlreadyList;
        }
    }
}
